#ifndef BIG_NUM_H
#define BIG_NUM_H

#include <string>
#include "BaseConverter.h"

class BigNum
{
private:
// typedefs
	typedef unsigned long pIntArrayType;

public:
// constructors
	BigNum();

	BigNum(std::string number);

	BigNum(const BigNum& bn);

	~BigNum();

// operators
	inline bool operator<(const BigNum& bn) const;
	
	BigNum& operator=(const BigNum& bn);

// methods
	bool IsPositive() const { return bIsPositive; }

	static std::string GetNumber(const BigNum &bn);

	static void Add(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Subtract(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Multiply(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Divide(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void LeftShift(const BigNum &bn, unsigned int shift_amt, BigNum &result, int num_threads = 1);

	static void RightShift(const BigNum &bn, unsigned int shift_amt, BigNum &result, int num_threads = 1);

	static void And(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Or(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Xor(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void Not(const BigNum &bn1, BigNum &result, int num_threads = 1);

	static bool Equal(const BigNum &bn1, const BigNum &bn2, int num_threads = 1);

private:
// helper functions
	void parse(std::string str);
	
	// resizes pIntArray and optionally copies values from old array to new array
	void resizeArray(unsigned int newCapacity, bool copyValue = true);

	static void addNoCheck(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static void subtractNoCheck(const BigNum &bn1, const BigNum &bn2, BigNum &result, int num_threads = 1);

	static BigNum::pIntArrayType BigNum::BigNum_atoi(const char* Str, char** EndPtr, int Radix);

	static char* BigNum::BigNum_itoa(pIntArrayType Value, char* Dest, int Radix);

	static const char* BigNum::getZeroString(int index);

private:
// fields
	pIntArrayType* pIntArray;
	bool bIsPositive;
	unsigned int size;
	unsigned int capacity;

	static const BaseConverter& dec2bin;
	static const BaseConverter& bin2dec;
};

#endif BIG_NUM_H